<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>移除大数组中多个指定索引元素</title>
</head>
<body>
<h2>移除大数组中多个指定索引元素性能测试</h2>
<p>测试数据为50万元素的数组，随机生成10000个要移除的索引</p>
<hr>
<div id="res"></div>

<script>
  const arrSize = 500000;
  const removeCount = 10000;

  function createArr() {
    const arr = [];
    for (let i = 0; i < arrSize; i++) {
      arr.push(i);
    }

    const indexes = new Set();
    while(indexes.size < removeCount) {
      const randomIndex = Math.floor(Math.random() * arrSize);
      indexes.add(randomIndex);
    }

    return {arr, indexes};
  }

  function showInfo(method, time, len) {
    const resDiv = document.createElement('div');
    resDiv.innerHTML = `
        <h4>${method}</h4><br>
        用时：${time.toFixed(3)}ms, 移除后数组长度为：${len}(预期长度：${arrSize-removeCount});<br>
        <hr>
        `;
    document.getElementById('res').appendChild(resDiv);
  }

  //方法1：splice反向排序索引后逐个删除
  function fun1(arr, indexes) {
    const copyArr = [...arr];
    const sortedIndexes = Array.from(indexes).sort((a, b) => b - a);
    for (const k of sortedIndexes) {
      copyArr.splice(k, 1);
    }
    return copyArr;
  }

  //方法2：filter
  function fun2(arr, indexes) {
    return arr.filter((_, index) => !indexes.has(index));
  }

  //方法3：reduce()
  function fun3(arr, indexes) {
    return arr.reduce((arr1, item, index) => {
      if(!indexes.has(index)) {
        arr1.push(item);
      }
      return arr1;
    }, []);
  }

  //方法4: fori循环
  function fun4(arr, indexes) {
    const result = [];
    for (let i = 0; i < arr.length; i++) {
      if(!indexes.has(i)) {
        result.push(arr[i]);
      }
    }
    return result;
  }

  //方法5: for...of循环
  function fun5(arr, indexes) {
    const result = [];
    let i = 0;
    for (const item of arr) {
      if(!indexes.has(i++)) {
        result.push(item);
      }
    }
    return result;
  }

  //方法6: forEach循环
  function fun6(arr, indexes) {
    const result = [];
    arr.forEach((item, index) => {
      if(!indexes.has(index)) {
        result.push(item);
      }
    });
    return result;
  }

  //方法7: 批量压入
  function fun7(arr, indexes) {
    const result = [];
    let start = 0;

    const sortedIndexes = Array.from(indexes).sort((a, b) => a - b);

    for (const index of sortedIndexes) {
      if (start < index) {
        result.push(...arr.slice(start, index));
      }
      start = index + 1;
    }

    if (start < arr.length) {
      result.push(...arr.slice(start));
    }

    return result;
  }

  function test() {
    const {arr, indexes} = createArr();
    const results = [];

    const tests = [
      {name: "方法1：splice反向删除", func: fun1},
      {name: "方法2：filter", func: fun2},
      {name: "方法3：reduce()", func: fun3},
      {name: "方法4：fori循环", func: fun4},
      {name: "方法5：for...of循环", func: fun5},
      {name: "方法6：forEach循环", func: fun6},
      {name: "方法7：批量压入", func: fun7}
    ];

    //预热
    tests.forEach(test => test.func([...arr], new Set(indexes)));

    //测试
    tests.forEach(test => {
      const arrCopy = [...arr];
      const indexesCopy = new Set(indexes);

      const start = performance.now();
      const result = test.func(arrCopy, indexesCopy);
      const time = performance.now() - start;

      results.push({
        method: test.name,
        time: time,
        len: result.length
      });
    });

    results.forEach(r => showInfo(r.method, r.time, r.len));
  }

  test();
</script>
</body>
</html>